package io.linfeng.modules.utils;

import cn.hutool.core.io.FileUtil;
import com.mchange.lang.ByteUtils;
import lombok.extern.slf4j.Slf4j;
import net.coobird.thumbnailator.Thumbnails;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

/**
 * 图片添加水印
 *
 * @author qzz
 */
@Slf4j
public class ImageUtils {


    // 用来调整水印的间距
    private static final int space = 40;

    public static void main(String[] args) throws IOException {
        // 读取原图片信息 得到文件（本地图片）
        File srcImgFile = new File("C:\\Users\\Administrator\\Desktop\\成品系统\\家装\\7777.png");

        String waterMarkContent = "杨师傅||2023-01-01||房间号：501";
        String[] waterMarkContents = waterMarkContent.split("\\|\\|");

        //将文件对象转化为图片对象
        Image srcImg = ImageIO.read(srcImgFile);
        //获取图片的宽
        int srcImgWidth = srcImg.getWidth(null);
        //获取图片的高
        int srcImgHeight = srcImg.getHeight(null);
        int fontSize = srcImg.getWidth(null) / 300 * 10;
        BufferedImage bufImg = new BufferedImage(srcImgWidth, srcImgHeight, BufferedImage.TYPE_INT_RGB);
        // 加水印
        //创建画笔
        Graphics2D g = bufImg.createGraphics();
        //绘制原始图片
        g.drawImage(srcImg, 0, 0, srcImgWidth, srcImgHeight, null);

        // 水印文件
        String waterMarkImage = "C:\\Users\\Administrator\\Desktop\\成品系统\\家装\\5555.png";
        Image srcWaterMark = ImageIO.read(new File(waterMarkImage));
        //获取水印图片的宽度
        int widthWaterMark = srcWaterMark.getWidth(null);
        //获取水印图片的高度
        int heightWaterMark = srcWaterMark.getHeight(null);
        //设置 alpha 透明度：alpha 必须是范围 [0.0, 1.0] 之内（包含边界值）的一个浮点数字
        g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, 0.9f));
        //绘制水印图片  坐标为中间位置
        g.drawImage(srcWaterMark, 0,
                (srcImgHeight - heightWaterMark), widthWaterMark, heightWaterMark, null);
        //        //根据图片的背景设置水印颜色
        g.setColor(new Color(32, 119, 188));
//        //设置字体  画笔字体样式为微软雅黑，加粗，文字大小为60pt
        g.setFont(new Font("微软雅黑", Font.BOLD, fontSize));
        // 获取水印文字的最大高度和宽度
        // 将换行后的文字放入新的集合
        ArrayList<String> waterMarkContentList = new ArrayList<>();
        for (String markContent : waterMarkContents) {
            // 单字符长度
            int tempCharLen = 0;
            // 单行字符总长度临时计算
            int tempLineLen = 0;
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < markContent.length(); i++) {
                char tempChar = markContent.charAt(i);
                tempCharLen = getCharLen(tempChar, g);
                tempLineLen += tempCharLen;
                // 文字长度大于图片宽度-2*间距-字体大小
                if (tempLineLen > srcImgWidth - space * 2 - tempCharLen) {
                    // 长度已经满一行
                    waterMarkContentList.add(sb.toString());
                    // 清空内容,重新追加
                    sb.delete(0, sb.length());
                    tempLineLen = 0;
                }
                // 追加字符
                sb.append(tempChar);
            }
            waterMarkContentList.add(sb.toString());
        }

        // 绘制水印
        int tempY = fontSize + space;
        for (int i = 0; i < waterMarkContentList.size(); i++) {
            String s = waterMarkContentList.get(i);
            //左上角
//                g.drawString(s, space, i * tempY + 2 * space);
            //右下角
            g.drawString(s, space, srcImgHeight - (waterMarkContentList.size() - i) * tempY + space);
        }
        g.dispose();
        //待存储的地址
        String tarImgPath = "C:\\Users\\Administrator\\Desktop\\成品系统\\家装\\2222.png";
        // 输出图片
        FileOutputStream outImgStream = new FileOutputStream(tarImgPath);
        ImageIO.write(bufImg, "png", outImgStream);
        log.debug("添加水印完成");
        outImgStream.flush();
        outImgStream.close();

    }

    /**
     * 上传图片加水印
     *
     * @param srcImgFile
     * @param targetPath
     * @param content
     */
    public static void imgWaterPress(File srcImgFile, String targetPath, String targetName, List<Graphics2DInfo> content,float quality) throws Exception {
        //将文件对象转化为图片对象
        Image srcImg = ImageIO.read(srcImgFile);
        //获取图片的宽
        int srcImgWidth = srcImg.getWidth(null);
        //获取图片的高
        int srcImgHeight = srcImg.getHeight(null);
        int fontSize = srcImg.getWidth(null) / 300 * 10;
        BufferedImage bufImg = new BufferedImage(srcImgWidth, srcImgHeight, BufferedImage.TYPE_INT_RGB);
        // 加水印
        //创建画笔
        Graphics2D g = bufImg.createGraphics();
        //绘制原始图片
        g.drawImage(srcImg, 0, 0, srcImgWidth, srcImgHeight, null);
        g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
        // 透明度
        float alpha = 0.5f;
        g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP,
                alpha));
        // 绘制几个水印/分成几份
        int num = 5;
        // 每一份x,y的大小
        int splitX = srcImgWidth / num, splitY = srcImgHeight / num;
        // 每一份中间的位置
        int centerX = splitX / 2, centerY = splitY / 2;
        int fontSize2 = (srcImgWidth + srcImgHeight) / 40;
        g.setFont(new Font("微软雅黑", Font.PLAIN, fontSize2));
        g.setColor(Color.white);
        // 设置旋转角度,可以为0-1
        g.rotate(0.2);
        for (int i = 1; i <= num; i++) {
            int x = splitX * i - centerX - fontSize, y = splitY * i - centerY - fontSize;
            g.drawString("https://xy2.ytl.asia", x, y);
        }
        g.dispose();


        int tempY = fontSize + space;
        for (int i = 0; i < content.size(); i++){
            Graphics2DInfo s = content.get(i);
            Graphics2D graphics = bufImg.createGraphics();
            graphics.setColor(s.getColor());
            graphics.setFont(new Font("微软雅黑", Font.BOLD, s.getSize(srcImgWidth)));
            if (s.getContent().contains(" ")) {
                String[] s1 = s.getContent().split(" ");
                int y = srcImgHeight - (content.size() - i) * tempY + space;
                graphics.drawString(s1[0], space, y);
                drawSpace(bufImg, space + getWatermarkLength(s1[0], graphics), y);
                graphics.drawString(s1[1], space + space + getWatermarkLength(s1[0], graphics), y);
                graphics.dispose();
                continue;
            }
            int y = srcImgHeight - (content.size() - i) * tempY + space;
            graphics.drawString(s.getContent(), space, y);
            graphics.dispose();
        }

        //待存储的地址
        String tarImgPath = targetPath;
        File tempFile = new File(tarImgPath);
        try {
            if (!tempFile.exists()) {
                tempFile.mkdirs();
            }
        } catch (Exception e) {
            e.getMessage();
        }
        // 输出图片
//        FileOutputStream outImgStream = new FileOutputStream(targetPath+File.separator+targetName);
        byte[] bytes = compressPic(bufImg, quality);


        FileUtil.writeBytes(bytes, targetPath+File.separator+targetName);
//        ImageIO.write(, "png", outImgStream);
        log.debug("添加水印完成");
//        outImgStream.flush();
//        outImgStream.close();




    }


    private static void drawSpace(BufferedImage bufferedImage,int x, int y){
        Graphics2D g = bufferedImage.createGraphics();
        g.setColor(new Color(249, 193, 61));
//        //设置字体  画笔字体样式为微软雅黑，加粗，文字大小为60pt fontSize
        g.setFont(new Font("微软雅黑", Font.BOLD, 70));
        g.drawString("|", x, y);
        g.dispose();
    }




//    java 输出流转化为输入流
//new ByteArrayInputStream(byteArrayOutputStream.toByteArray());


    /**
     * 输入流转byte[ ]
     *
     * @param inStream
     * @return
     * @throws IOException
     */
    private static final byte[] input2byte(InputStream inStream)
            throws IOException {
        ByteArrayOutputStream swapStream = new ByteArrayOutputStream();
        byte[] buff = new byte[100];
        int rc = 0;
        while ((rc = inStream.read(buff, 0, 100)) > 0) {
            swapStream.write(buff, 0, rc);
        }
        byte[] in2b = swapStream.toByteArray();
        return in2b;
    }


    /**
     * @param
     * @param outputFile
     * @return
     */
    public static File writeBytesToFile(byte[] b, String outputFile) {
        File file = null;
        FileOutputStream os = null;
        try {
            file = new File(outputFile);
            os = new FileOutputStream(file);
            os.write(b);
        } catch (Exception var13) {
            var13.printStackTrace();
        } finally {
            try {
                if (os != null) {
                    os.close();
                }
            } catch (IOException var12) {
                var12.printStackTrace();
            }
        }
        return file;
    }

    // outputStream转inputStream
    public static ByteArrayInputStream parse(OutputStream out) throws Exception {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        baos = (ByteArrayOutputStream) out;
        ByteArrayInputStream swapStream = new ByteArrayInputStream(baos.toByteArray());
        return swapStream;
    }


//    /**
//     * 获取水印文字的长度
//     * @param waterMarkContent
//     * @param g
//     * @return
//     */
//    public static int getWatermarkLength(String waterMarkContent, Graphics2D g) {
//        return g.getFontMetrics(g.getFont()).charsWidth(waterMarkContent.toCharArray(), 0, waterMarkContent.length());
//    }


    /**
     * 方式二压缩 Google大法 因为Thumbnails.of() 方法是一个重载方法，参数不仅仅局限于是一个文件类型 可以是以流的形式 File形式，ImageBuffer对象，URL路径,String类型指定文件路径
     * 然后可通过链式构造器传入不通参数，压缩比例，指定输出的格式等最终通过toFile("文件存储路径")返回一个已经压缩完成的图片。
     * @param file 待压缩的文件
     * @return 压缩后图片路径 这个可自己指定
     */
    public static void thumbnail(MultipartFile file) {
        //得到上传时的原文件名
        String originalFilename = file.getOriginalFilename();
        //获取文件格式
        String ext = originalFilename.substring(originalFilename.lastIndexOf(".") + 1);
        //获取uuid作为文件名
        String name = UUID.randomUUID().toString().replaceAll("-", "");
        try {
            // 先尝试压缩并保存图片
            Thumbnails.of(file.getInputStream()).scale(0.5f)
                    .outputQuality(0.15f)
                    .outputFormat("jpeg")
                    .toFile("/image/" + name);
        } catch (IOException e) {

        }
    }




    public static int getCharLen(char c, Graphics2D g) {
        return g.getFontMetrics(g.getFont()).charWidth(c);
    }

    /**
     * 获取水印文字总长度
     *
     * @param waterMarkContent 水印的文字
     * @param g                绘图方法
     * @return 水印文字总长度
     */
    public static int getWatermarkLength(String waterMarkContent, Graphics2D g) {
        return g.getFontMetrics(g.getFont()).charsWidth(waterMarkContent.toCharArray(), 0, waterMarkContent.length());
    }


    /**
     *
     * @param image
     * @param quality 参数qality是取值0~1范围内，压缩程度
     * @return
     * @throws IOException
     */
    public static byte[] compressPic(BufferedImage image, float quality) throws IOException {
        ByteArrayOutputStream outArray = new ByteArrayOutputStream();
        // 指定写图片的方式为 jpg
        ImageWriter imgWrier = ImageIO.getImageWritersByFormatName("jpg").next();
        ImageWriteParam imgWriteParams = new javax.imageio.plugins.jpeg.JPEGImageWriteParam(null);
        // 要使用压缩，必须指定压缩方式为MODE_EXPLICIT
        imgWriteParams.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
        // 设置压缩质量参数，参数qality是取值0~1范围内，
        imgWriteParams.setCompressionQuality(quality);
        imgWriteParams.setProgressiveMode(ImageWriteParam.MODE_DISABLED);
        ColorModel colorModel = image.getColorModel();
        // 指定压缩时使用的色彩模式
        imgWriteParams.setDestinationType(
                new ImageTypeSpecifier(colorModel, colorModel.createCompatibleSampleModel(16, 16)));
        try {
            imgWrier.reset();
            // 必须先指定 out值，才能调用write方法, ImageOutputStream可以通过任何
            // OutputStream构造
            imgWrier.setOutput(ImageIO.createImageOutputStream(outArray));
            // 调用write方法，就可以向输入流写图片
            imgWrier.write(null, new IIOImage(image, null, null), imgWriteParams);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            imgWrier.dispose();
        }
        return outArray.toByteArray();
    }
}
